Skip to content

feat: add MIME-aware file icons - #28

Merged
Athemis merged 3 commits into
mainfrom
feat/placeholder-images
Dec 10, 2025
Merged

feat: add MIME-aware file icons#28
Athemis merged 3 commits into
mainfrom
feat/placeholder-images

Conversation

@Athemis

@Athemis Athemis commented Dec 10, 2025

Copy link
Copy Markdown
Owner

Summary

  • Show placeholder icons for non-image attachments where no thumbnail is available
  • Icons are chosen based on mime type with fallback to generic file icon

Testing

  • cargo fmt
  • cargo clippy --all-targets --all-features
  • cargo test
  • cargo doc --no-deps

Platforms exercised (mark all that apply):

  • Windows
  • macOS
  • Linux

Screenshots (if UI changes)

image

Docs/metadata

  • README/CONTRIBUTING updated if behavior or commands changed
  • User Guide updated (if user-facing change)

Notes for reviewers

Summary by CodeRabbit

  • New Features

    • Attachment list now shows file-type icons for unknown thumbnails.
  • Improvements

    • Dedicated thumbnail areas display a centered placeholder icon while images load or after failure.
    • Thumbnail loading is de-duplicated to reduce redundant requests and improve responsiveness.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Dec 10, 2025

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Athemis has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 17 minutes and 35 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 8ff6e76 and b225b46.

📒 Files selected for processing (1)
  • src/ui/components/attachments.rs (6 hunks)

Walkthrough

These changes add a MIME-based icon utility and integrate thumbnail loading state into the attachments UI: thumbnails are tracked as in-flight, cached or failed thumbnails influence rendering, and MIME-appropriate placeholder icons are shown in a dedicated thumbnail rect when needed.

Changes

Cohort / File(s) Summary
File Icon Utility Module
src/utils/file_icons.rs
New public module adding pub fn icon_for(mime: &str, path: &Path) -> &'static str that maps MIME types and file extensions to Phosphor icon identifiers with fallbacks and archive detection.
Utility Module Exports
src/utils/mod.rs
Exposes file_icons module and re-exports icon_for alongside sanitize_component.
Attachment Rendering & State
src/ui/components/attachments.rs
Adds thumbnail_loading: HashSet<PathBuf> to AttachmentsModel; prevents duplicate thumbnail loads, records thumbnail ready/failed states keyed by path, allocates 96×72 thumbnail rects, renders cached thumbnails scaled, and renders MIME-appropriate placeholder icons (via icon_for) when loading/failure/non-image. Adds render_placeholder_icon() helper.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review new MIME-to-icon mappings and edge-case handling in src/utils/file_icons.rs.
  • Verify thumbnail-loading concurrency guard and correct path-keying in src/ui/components/attachments.rs.
  • Confirm UI sizing/placement and scaling logic for rendered thumbnails and placeholder icons.

Poem

"Make it so: a thumbnail that waits in light,

Icons stand ready when pixels take flight.

Paths marked 'loading' hold steady and true—

Mime sings its token; the view comes through. 🖼️✨"

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add MIME-aware file icons' directly and clearly describes the primary change—adding MIME-aware icon selection for file attachments.
Description check ✅ Passed The description covers the summary and testing checklist comprehensively, includes a screenshot, and marks platform testing. However, the 'Manual test steps' and 'Notes for reviewers' sections are empty, which are non-critical gaps.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/ui/components/attachments.rs (1)

259-272: Acknowledged. The thumbnail rendering logic is sound.

The implementation correctly handles three scenarios: cached thumbnails, pending image loads, and non-image placeholders. The allocated space ensures consistent layout.

One consideration for future refinement: images awaiting their first thumbnail load display blank space until the texture arrives. Showing a temporary placeholder icon during initial load would provide more immediate visual feedback. However, the current approach is acceptable and allows the thumbnail to appear without a distracting icon swap.

src/utils/file_icons.rs (2)

31-140: A thorough and methodical implementation, Commander.

The icon selection logic comprehensively covers media types, document formats, and programming languages. The cascading checks prioritize MIME types while providing extension-based fallbacks, and the case-insensitive matching prevents user frustration.

One minor observation: OpenDocument formats (ODS, ODP) return FILE_TEXT rather than spreadsheet or presentation icons. If more specific icons are available in the Phosphor set, consider FILE_XLS for ODS and FILE_PPT for ODP to better convey their purpose. However, the current choice is acceptable.

The Rust compiler will verify all Phosphor icon constants at build time, providing assurance that no typos will reach production.


142-163: A capable archive detection routine, but documentation would serve us well.

The function correctly identifies archive formats through MIME types, extensions, and composite suffixes like .tar.gz. The composite extension checking is particularly valuable since Path::extension() would miss these.

Consider adding a rustdoc comment explaining the rationale for checking filename suffixes, as this aids maintainability. For example:

/// Detect archive files by MIME, extension, and composite suffixes.
///
/// Composite suffixes like `.tar.gz` are checked via filename since
/// `Path::extension()` would only detect `gz`.
fn is_archive_mime(mime: &str, ext: &str, fname: &str) -> bool {

Additionally, for defensive robustness against MIME detection failures, consider adding extension checks for common formats already covered by MIME:

     || ext == "rar"
     || ext == "7z"
+    || ext == "zip"
+    || ext == "tar"
+    || ext == "gz"
     || ext == "xz"
     || ext == "zst"
     || ext == "bz2"

This provides a fallback path when MIME detection is unavailable or incorrect.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 252d236 and 8ff6e76.

📒 Files selected for processing (3)
  • src/ui/components/attachments.rs (3 hunks)
  • src/utils/file_icons.rs (1 hunks)
  • src/utils/mod.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Entry point at src/main.rs which calls app::run() to start eframe/egui. Add SPDX headers on all source files: SPDX-License-Identifier: MIT plus one or more SPDX-FileCopyrightText lines naming actual authors.
Commands (PickFiles, HashFile, LoadThumbnail, SaveArchive) perform side-effects via run_command and emit follow-up messages back into the update loop for re-rendering.
Follow rustfmt defaults with 4-space indent and trailing commas where appropriate; run cargo fmt before committing.
Use snake_case for functions, variables, and filenames; use CamelCase for types; keep module files small and focused.
Use English language within the codebase.
Use code comments sparingly to explain intent, invariants, or non-obvious control flow; avoid restating what the code already makes clear.
Use rustdoc with /// for public items and //! for module-level docs; start with one-line summary ending with period; structure details with # headings (e.g., # Examples, # Errors, # Panics, # Safety, # Performance).
Include small, runnable examples marked no_run/ignore in rustdoc when side effects exist; keep examples minimal and dependency-free.
In rustdoc, explain invariants, panics, and error cases explicitly; prefer present tense and describe behavior, not intent.
Use intra-doc links in rustdoc like [`TypeName`] or [`module::function`]; disambiguate with full paths when needed.
Document private helpers in rustdoc when it aids maintainers; keep explanations concise.

Files:

  • src/utils/file_icons.rs
  • src/utils/mod.rs
  • src/ui/components/attachments.rs
{**/*.rs,tests/**/*.rs}

📄 CodeRabbit inference engine (AGENTS.md)

Use cargo test for unit and integration coverage; colocate simple unit tests with modules and broader scenarios under tests/. Name tests after behavior (e.g., submits_trimmed_input) and keep them deterministic.

Files:

  • src/utils/file_icons.rs
  • src/utils/mod.rs
  • src/ui/components/attachments.rs
{src/ui/**/*.rs,src/ui/components/**/*.rs}

📄 CodeRabbit inference engine (AGENTS.md)

{src/ui/**/*.rs,src/ui/components/**/*.rs}: UI components in src/ui/ and src/ui/components/* must remain side-effect free and emit messages only; all validation and state transitions belong in src/mvu/ or model/logic modules; IO happens only in commands executed by run_command.
Use Phosphor icons via egui_phosphor::regular::NAME (with RichText or button labels) instead of embedding SVGs. The font is registered in src/main.rs. Keep icon+text buttons short using format!("{} Label", icon) and reuse existing helpers in src/ui.rs.

Files:

  • src/ui/components/attachments.rs
src/ui/components/attachments.rs

📄 CodeRabbit inference engine (AGENTS.md)

src/ui/components/attachments.rs implements attachments panel with list, thumbnails, inline filename editing; computes sanitized_name using sanitize_component; shows WARNING icon on sanitized mismatch; emits commands for file picking/hashing/thumbnails; sanitizes and dedupes edited names.

Files:

  • src/ui/components/attachments.rs
{src/ui/**/*.rs,src/app/**/*.rs}

📄 CodeRabbit inference engine (AGENTS.md)

No external assets are fetched at runtime; all UI is generated by egui at runtime.

Files:

  • src/ui/components/attachments.rs
{src/mvu/**/*.rs,src/ui/**/*.rs}

📄 CodeRabbit inference engine (AGENTS.md)

File dialog operations use rfd crate for cross-platform native dialogs.

Files:

  • src/ui/components/attachments.rs
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to src/ui/components/attachments.rs : `src/ui/components/attachments.rs` implements attachments panel with list, thumbnails, inline filename editing; computes `sanitized_name` using `sanitize_component`; shows WARNING icon on sanitized mismatch; emits commands for file picking/hashing/thumbnails; sanitizes and dedupes edited names.
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to {src/ui/**/*.rs,src/ui/components/**/*.rs} : Use Phosphor icons via `egui_phosphor::regular::NAME` (with `RichText` or button labels) instead of embedding SVGs. The font is registered in `src/main.rs`. Keep icon+text buttons short using `format!("{} Label", icon)` and reuse existing helpers in `src/ui.rs`.
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to {src/ui/**/*.rs,src/ui/components/**/*.rs} : Use Phosphor icons via `egui_phosphor::regular::NAME` (with `RichText` or button labels) instead of embedding SVGs. The font is registered in `src/main.rs`. Keep icon+text buttons short using `format!("{} Label", icon)` and reuse existing helpers in `src/ui.rs`.

Applied to files:

  • src/utils/file_icons.rs
  • src/utils/mod.rs
  • src/ui/components/attachments.rs
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to {src/mvu/**/*.rs,src/ui/**/*.rs} : File dialog operations use `rfd` crate for cross-platform native dialogs.

Applied to files:

  • src/utils/file_icons.rs
  • src/utils/mod.rs
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to src/ui/components/attachments.rs : `src/ui/components/attachments.rs` implements attachments panel with list, thumbnails, inline filename editing; computes `sanitized_name` using `sanitize_component`; shows WARNING icon on sanitized mismatch; emits commands for file picking/hashing/thumbnails; sanitizes and dedupes edited names.

Applied to files:

  • src/utils/file_icons.rs
  • src/utils/mod.rs
  • src/ui/components/attachments.rs
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to src/logic/eln.rs : `src/logic/eln.rs` builds and writes ELN RO-Crate metadata, generates suggested archive names, and conforms to RO-Crate 1.2 and ELN File Format specification; uses pre-sanitized names from attachments; has no UI dependencies.

Applied to files:

  • src/utils/file_icons.rs
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to **/*.rs : Use rustdoc with `///` for public items and `//!` for module-level docs; start with one-line summary ending with period; structure details with `#` headings (e.g., `# Examples`, `# Errors`, `# Panics`, `# Safety`, `# Performance`).

Applied to files:

  • src/utils/file_icons.rs
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Organize code: Pure data in `src/models/`; business/format logic in `src/logic/eln.rs`; MVU kernel in `src/mvu/`; UI composition in `src/ui/`; components in `src/ui/components/`; utilities in `src/utils/`.

Applied to files:

  • src/utils/mod.rs
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to {src/logic/**/*.rs,tests/**/*.rs} : Test business logic in `src/logic/eln.rs` independently of UI; mock file system operations where appropriate.

Applied to files:

  • src/utils/mod.rs
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to {src/ui.rs,src/logic/eln.rs} : Separate UI concerns in `src/ui.rs` from business logic in `src/logic/eln.rs` for maintainability and testability.

Applied to files:

  • src/utils/mod.rs
📚 Learning: 2025-12-03T16:16:45.376Z
Learnt from: CR
Repo: Athemis/ELNPack PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T16:16:45.376Z
Learning: Applies to src/ui.rs : UI strings live directly in `src/ui.rs` within the egui code; prefer short, actionable labels.

Applied to files:

  • src/ui/components/attachments.rs
🧬 Code graph analysis (2)
src/utils/mod.rs (2)
src/utils/sanitize_component.rs (1)
  • sanitize_component (26-119)
src/utils/file_icons.rs (1)
  • icon_for (13-140)
src/ui/components/attachments.rs (2)
src/utils/file_icons.rs (1)
  • icon_for (13-140)
src/utils/sanitize_component.rs (1)
  • sanitize_component (26-119)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (7)
src/utils/mod.rs (2)

6-6: Engage. The new module integration proceeds smoothly.

The public module declaration and re-export are properly structured. The documentation, while brief, adequately conveys the function's purpose in the manner befitting a utility module index.

Also applies to: 10-11


15-15: Make it so. The sanitize_component re-export is correctly positioned.

The public re-export maintains consistency with the module's API structure.

src/ui/components/attachments.rs (3)

14-14: Proceed. The import statement is properly configured.

The addition of icon_for to the existing utility imports is logically sound and maintains module cohesion.


251-252: Excellent work. The icon determination is logically positioned.

Computing the icon once per attachment and storing it for subsequent use demonstrates sound engineering practice.


523-543: Well done, Number One. The placeholder rendering function is exemplary.

The implementation achieves visual clarity through centered icon text with appropriate scaling and a subtle outline. The color and styling choices integrate seamlessly with egui's theme system.

src/utils/file_icons.rs (2)

1-9: Engage. The module header and documentation meet Starfleet standards.

The SPDX headers are properly declared, and the module documentation clearly articulates the utility's purpose and design philosophy. The UI-agnostic approach demonstrates sound architectural thinking.


12-29: Proceed. The parameter extraction is executed with precision.

The MIME type normalization properly handles charset parameters, and the extension and filename extraction employ robust null-safe patterns. The case-insensitive matching prevents subtle errors.

@Athemis
Athemis marked this pull request as ready for review December 10, 2025 15:47
@Athemis
Athemis merged commit ccdb727 into main Dec 10, 2025
9 of 10 checks passed
This was referenced Dec 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant